import re
import inspect
import traceback
from flask import request
from flasgger import Swagger, SwaggerView
from src.utils.logger import log_error, log_info

class SwaggerAutoConfig:
    """自动为Flask路由生成Swagger文档配置"""
    
    def __init__(self, app=None, config=None):
        self.app = app
        self.config = config or {
            "swagger": "2.0",
            "info": {
                "title": "视频处理工具 API",
                "description": "视频分类、混搭和音频合成的API接口",
                "version": "1.0"
            },
            "termsOfService": "",
            "headers": [],
            "specs": [
                {
                    "endpoint": "apispec",
                    "route": "/api/apispec.json",
                    "rule_filter": lambda rule: True,
                    "model_filter": lambda tag: True,
                }
            ],
            "specs_route": "/api/docs",
            "static_url_path": "/api/flasgger_static",
            "swagger_ui": True,
            "uiversion": 3
        }
        
        if app:
            self.init_app(app)
    
    def init_app(self, app):
        """初始化应用程序"""
        self.app = app
        
        # 添加错误处理路由，用于捕获和记录Swagger错误
        @app.route('/api/swagger-error', methods=['GET'])
        def swagger_error_handler():
            log_error("Swagger API规范生成失败，查看日志获取更多信息")
            return {"error": "Failed to generate Swagger specification"}, 500
            
        # 开始应用自动配置
        try:
            self._patch_routes()
            
            # 增加安全处理
            def apispec_wrapper(*args, **kwargs):
                try:
                    from flasgger.utils import get_specs
                    return get_specs(*args, **kwargs)
                except Exception as e:
                    log_error(f"生成API规范时发生错误: {str(e)}")
                    log_error(traceback.format_exc())
                    return {"error": "Failed to generate API specification"}, 500
            
            # 替换flasgger的apispec端点处理函数，添加错误处理
            for spec in self.config['specs']:
                if spec['endpoint'] == 'apispec':
                    app.view_functions[spec['endpoint']] = apispec_wrapper
            
            # 初始化Swagger
            Swagger(app, config=self.config)
            log_info("Swagger 配置已成功初始化")
            
        except Exception as e:
            log_error(f"初始化Swagger时发生错误: {str(e)}")
            log_error(traceback.format_exc())
    
    def _patch_routes(self):
        """为所有路由添加Swagger规范"""
        for endpoint, view_func in self.app.view_functions.items():
            if not endpoint.startswith('static') and not endpoint.startswith('flasgger'):
                # 获取路由规则
                for rule in self.app.url_map.iter_rules():
                    if rule.endpoint == endpoint:
                        try:
                            # 自动生成Swagger规范
                            self._add_swagger_spec(view_func, rule)
                        except Exception as e:
                            log_error(f"为路由 {rule} 添加Swagger规范时出错: {str(e)}")
    
    def _add_swagger_spec(self, view_func, rule):
        """为视图函数添加Swagger规范"""
        # 基本参数
        path_params = [p for p in rule.arguments]
        http_methods = list(rule.methods - {'OPTIONS', 'HEAD'})
        
        # 如果函数没有文档字符串，添加一个基本的
        if not view_func.__doc__:
            module_name = view_func.__module__.split('.')[-1].replace('_routes', '')
            function_name = view_func.__name__.replace('_', ' ')
            view_func.__doc__ = f"{module_name.capitalize()} - {function_name}"
        
        # 解析函数参数和请求体
        spec = self._parse_function(view_func, rule)
        
        # 为视图函数添加swagger_from_spec属性
        view_func.swag = spec
        
        try:
            # 修改__doc__为swagger兼容格式
            view_func.__doc__ = self._format_docstring(view_func.__doc__, spec)
        except Exception as e:
            log_error(f"格式化路由 {rule} 的文档字符串时出错: {str(e)}")
            # 使用简单的文档字符串作为备用
            view_func.__doc__ = view_func.__doc__.strip() + "\n---\ntags:\n  - API\nresponses:\n  200:\n    description: 成功响应"
    
    def _format_docstring(self, original_doc, spec):
        """格式化文档字符串，使之与Swagger兼容"""
        try:
            swagger_doc = original_doc.strip() + "\n---\n"
            
            # 添加请求内容类型
            if spec.get("consumes"):
                swagger_doc += "consumes:\n"
                for consume in spec["consumes"]:
                    swagger_doc += f"  - {consume}\n"
            
            # 添加标签
            if spec.get("tags"):
                swagger_doc += "tags:\n"
                for tag in spec["tags"]:
                    swagger_doc += f"  - {tag}\n"
            
            # 添加参数
            if spec.get("parameters"):
                swagger_doc += "parameters:\n"
                for param in spec["parameters"]:
                    if param["in"] == "path":
                        swagger_doc += f"  - name: {param['name']}\n"
                        swagger_doc += f"    in: {param['in']}\n"
                        swagger_doc += f"    required: {str(param['required']).lower()}\n"
                        swagger_doc += f"    type: {param['type']}\n"
                        swagger_doc += f"    description: {param['description']}\n"
                    elif param["in"] == "body":
                        swagger_doc += f"  - name: {param['name']}\n"
                        swagger_doc += f"    in: {param['in']}\n"
                        swagger_doc += f"    required: {str(param['required']).lower()}\n"
                        swagger_doc += f"    schema:\n"
                        swagger_doc += f"      type: {param['schema']['type']}\n"
                        if 'properties' in param['schema']:
                            swagger_doc += f"      properties:\n"
                            for prop_name, prop_spec in param['schema']['properties'].items():
                                swagger_doc += f"        {prop_name}:\n"
                                swagger_doc += f"          type: {prop_spec['type']}\n"
                                swagger_doc += f"          description: {prop_spec['description']}\n"
                                if 'default' in prop_spec:
                                    if prop_spec['type'] == 'string':
                                        swagger_doc += f"          default: '{prop_spec['default']}'\n"
                                    else:
                                        swagger_doc += f"          default: {prop_spec['default']}\n"
                    elif param["in"] == "query":  # 添加对查询参数的支持
                        swagger_doc += f"  - name: {param['name']}\n"
                        swagger_doc += f"    in: {param['in']}\n"
                        swagger_doc += f"    required: {str(param['required']).lower()}\n"
                        swagger_doc += f"    type: {param['type']}\n"
                        swagger_doc += f"    description: {param['description']}\n"
                        if 'default' in param:
                            if param['type'] == 'string':
                                swagger_doc += f"    default: '{param['default']}'\n"
                            else:
                                swagger_doc += f"    default: {param['default']}\n"
                    elif param["in"] == "formData":  # 添加对表单数据的支持
                        swagger_doc += f"  - name: {param['name']}\n"
                        swagger_doc += f"    in: {param['in']}\n"
                        swagger_doc += f"    required: {str(param['required']).lower()}\n"
                        swagger_doc += f"    type: {param['type']}\n"
                        swagger_doc += f"    description: {param['description']}\n"
                        if 'default' in param:
                            if param['type'] == 'string':
                                swagger_doc += f"    default: '{param['default']}'\n"
                            else:
                                swagger_doc += f"    default: {param['default']}\n"
            
            # 添加响应
            swagger_doc += "responses:\n"
            for code, response in spec["responses"].items():
                swagger_doc += f"  {code}:\n"
                swagger_doc += f"    description: {response['description']}\n"
            
            return swagger_doc
        except Exception as e:
            log_error(f"格式化文档字符串时出错: {str(e)}")
            # 返回一个简单但有效的文档字符串
            return original_doc.strip() + "\n---\ntags:\n  - API\nresponses:\n  200:\n    description: 成功响应"
    
    def _parse_function(self, view_func, rule):
        """分析函数代码，提取请求参数和响应结构"""
        try:
            spec = {
                "tags": [rule.rule.split('/')[2] if len(rule.rule.split('/')) > 2 else "default"],
                "parameters": [],
                "responses": {
                    "200": {
                        "description": "成功响应"
                    }
                }
            }
            
            # 添加路径参数
            for arg in rule.arguments:
                param = {
                    "name": arg,
                    "in": "path",
                    "required": True,
                    "type": "string",
                    "description": f"路径参数 {arg}"
                }
                spec["parameters"].append(param)
            
            # 尝试分析函数源码提取参数
            source = inspect.getsource(view_func)
            
            # 检测URL查询参数
            if "request.args" in source:
                # 提取查询参数
                query_pattern = r"request\.args\.get\(['\"](\w+)['\"](?:,\s*([^)]+))?\)"
                query_matches = re.findall(query_pattern, source)
                
                for param_name, default_value in query_matches:
                    param_type = "string"  # 默认类型
                    description = f"查询参数 {param_name}"
                    required = False
                    
                    # 根据默认值推断类型
                    if default_value:
                        if default_value.strip() == "True" or default_value.strip() == "False":
                            param_type = "boolean"
                        elif default_value.strip().isdigit() or (default_value.strip().startswith("int(") and default_value.strip().endswith(")")):
                            param_type = "integer"
                        elif default_value.strip().startswith("'") or default_value.strip().startswith('"'):
                            param_type = "string"
                    elif param_name.endswith('_id') or param_name == 'id':
                        param_type = "string"
                    elif param_name.startswith('is_') or param_name.endswith('_flag'):
                        param_type = "boolean"
                    elif param_name.endswith('_count') or param_name.endswith('_number') or param_name == 'page' or param_name == 'page_size':
                        param_type = "integer"
                    
                    # 检查是否是必需参数
                    required_pattern = rf"if\s+not\s+{param_name}:"
                    if re.search(required_pattern, source):
                        required = True
                    
                    query_param = {
                        "name": param_name,
                        "in": "query",
                        "required": required,
                        "type": param_type,
                        "description": description
                    }
                    
                    # 如果有默认值，添加
                    if default_value and default_value.strip() != "None":
                        try:
                            if param_type == "boolean":
                                query_param["default"] = eval(default_value.strip())
                            elif param_type == "integer":
                                if default_value.strip().startswith("int("):
                                    inner_value = default_value.strip()[4:-1]
                                    query_param["default"] = int(eval(inner_value))
                                else:
                                    query_param["default"] = int(default_value.strip())
                            elif param_type == "string" and (default_value.strip().startswith("'") or default_value.strip().startswith('"')):
                                query_param["default"] = default_value.strip().strip("'\"")
                        except:
                            pass
                    
                    spec["parameters"].append(query_param)
            
            # 检测文件上传 API
            if "request.files" in source:
                # 设置为文件上传格式
                spec["consumes"] = ["multipart/form-data"]
                
                # 提取文件参数
                file_pattern = r"request\.files\s*\[\s*['\"](\w+)['\"]"
                file_matches = re.findall(file_pattern, source)
                
                for file_param in file_matches:
                    spec["parameters"].append({
                        "name": file_param,
                        "in": "formData",
                        "required": True,
                        "type": "file",
                        "description": f"{file_param} 文件"
                    })
                
                # 提取表单参数
                form_pattern = r"request\.form\.get\(['\"](\w+)['\"](?:,\s*([^)]+))?\)"
                form_matches = re.findall(form_pattern, source)
                
                for param_name, default_value in form_matches:
                    param_type = "string"  # 默认类型
                    description = f"表单参数 {param_name}"
                    
                    # 根据默认值推断类型
                    if default_value:
                        if default_value.strip() == "True" or default_value.strip() == "False":
                            param_type = "boolean"
                        elif default_value.strip().isdigit():
                            param_type = "integer"
                        elif default_value.strip().startswith("'") or default_value.strip().startswith('"'):
                            param_type = "string"
                    
                    form_param = {
                        "name": param_name,
                        "in": "formData",
                        "required": False,  # 表单参数通常是可选的
                        "type": param_type,
                        "description": description
                    }
                    
                    # 如果有默认值，添加
                    if default_value and default_value.strip() != "None":
                        try:
                            if param_type == "boolean":
                                form_param["default"] = eval(default_value.strip())
                            elif param_type == "integer":
                                form_param["default"] = int(default_value.strip())
                            elif param_type == "string" and (default_value.strip().startswith("'") or default_value.strip().startswith('"')):
                                form_param["default"] = default_value.strip().strip("'\"")
                        except:
                            pass
                    
                    spec["parameters"].append(form_param)
            
            # 处理 JSON 请求参数 - 增强版
            elif ("POST" in rule.methods or "PUT" in rule.methods) and ("request.json" in source or "request.get_json()" in source):
                # 检测 JSON 数据访问模式
                # 1. 检测变量赋值 - 例如 data = request.json
                json_var_pattern = r"(\w+)\s*=\s*request\.(?:json|get_json\(\))"
                json_var_match = re.search(json_var_pattern, source)
                
                json_var_name = None
                if json_var_match:
                    json_var_name = json_var_match.group(1)
                
                # 收集参数 - 支持多种访问模式
                param_matches = []
                
                # 模式1: data.get('param') 
                if json_var_name:
                    var_get_pattern = rf"{json_var_name}\.get\(['\"](\w+)['\"](?:,\s*([^)]+))?\)"
                    param_matches.extend(re.findall(var_get_pattern, source))
                
                # 模式2: request.json.get('param')
                direct_get_pattern = r"request\.json\.get\(['\"](\w+)['\"](?:,\s*([^)]+))?\)"
                param_matches.extend(re.findall(direct_get_pattern, source))
                
                # 模式3: data['param']
                if json_var_name:
                    var_bracket_pattern = rf"{json_var_name}\s*\[\s*['\"](\w+)['\"]"
                    bracket_matches = re.findall(var_bracket_pattern, source)
                    param_matches.extend([(param, '') for param in bracket_matches])
                
                # 模式4: request.json['param']
                direct_bracket_pattern = r"request\.json\s*\[\s*['\"](\w+)['\"]"
                direct_bracket_matches = re.findall(direct_bracket_pattern, source)
                param_matches.extend([(param, '') for param in direct_bracket_matches])
                
                if param_matches:
                    # 添加请求体参数架构
                    body_schema = {
                        "name": "body",
                        "in": "body",
                        "required": True,
                        "schema": {
                            "type": "object",
                            "properties": {}
                        }
                    }
                    
                    # 去重
                    unique_params = {}
                    for param_name, default_value in param_matches:
                        if param_name in unique_params:
                            continue
                        unique_params[param_name] = default_value
                    
                    for param_name, default_value in unique_params.items():
                        param_type = "string"  # 默认类型
                        description = f"参数 {param_name}"
                        
                        # 根据变量名特征推断类型
                        if default_value:
                            if default_value.strip() == "True" or default_value.strip() == "False":
                                param_type = "boolean"
                            elif default_value.strip().isdigit():
                                param_type = "integer"
                            elif default_value.strip().startswith("'") or default_value.strip().startswith('"'):
                                param_type = "string"
                        elif param_name.endswith('_id') or param_name == 'id':
                            param_type = "string"  # ID通常是字符串
                        elif param_name.startswith('is_') or param_name.endswith('_flag'):
                            param_type = "boolean"  # 布尔标志
                        elif param_name.endswith('_count') or param_name.endswith('_number'):
                            param_type = "integer"  # 数字类型
                        
                        body_schema["schema"]["properties"][param_name] = {
                            "type": param_type,
                            "description": description
                        }
                        
                        # 如果有默认值，添加
                        if default_value:
                            try:
                                if param_type == "boolean":
                                    eval_default = eval(default_value.strip())
                                    body_schema["schema"]["properties"][param_name]["default"] = eval_default
                                elif param_type == "integer":
                                    body_schema["schema"]["properties"][param_name]["default"] = int(default_value.strip())
                                elif param_type == "string" and (default_value.strip().startswith("'") or default_value.strip().startswith('"')):
                                    clean_value = default_value.strip().strip("'\"")
                                    body_schema["schema"]["properties"][param_name]["default"] = clean_value
                            except:
                                pass
                    
                    # 从源码推断必需字段
                    required_fields = []
                    if json_var_name:
                        for param_name in unique_params.keys():
                            required_pattern = rf"if\s+not\s+(?:{json_var_name}\s*\[\s*['\"]?{param_name}['\"]?\s*\]|{json_var_name}\.get\(['\"]?{param_name}['\"]?\))"
                            if re.search(required_pattern, source):
                                required_fields.append(param_name)
                    
                    if required_fields:
                        body_schema["schema"]["required"] = required_fields
                    
                    spec["parameters"].append(body_schema)
            
            # 尝试识别响应结构
            if "return jsonify" in source or "return {" in source:
                # 检测错误响应码
                status_pattern = r"return\s+(?:jsonify\(\S*\)|{[^}]*})\s*,\s*(\d+)"
                status_matches = re.findall(status_pattern, source)
                
                for status_code in status_matches:
                    if status_code not in spec["responses"]:
                        description = "错误响应"
                        if status_code == "400":
                            description = "请求参数错误"
                        elif status_code == "404":
                            description = "资源未找到"
                        elif status_code == "500":
                            description = "服务器内部错误"
                            
                        spec["responses"][status_code] = {
                            "description": description
                        }
            
            return spec
        
        except Exception as e:
            log_error(f"解析视图函数 {view_func.__name__} 错误: {str(e)}")
            log_error(traceback.format_exc())
            # 返回一个基本的规范，确保不会崩溃
            return {
                "tags": ["API"],
                "parameters": [],
                "responses": {"200": {"description": "成功响应"}}
            }